#pragma once

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>

#include "Cond.hpp"
#include "Mutex.hpp"
using namespace CondMoudle;
using namespace MutexModule;

const int bqsize = 5;

template <typename T>
class BlockQueue
{
private:
    bool isfull()
    {
        return _q.size() == _cap;
    }

    bool isempty()
    {
        return _q.size() == 0;
    }

public:
    BlockQueue()
        : _p_num(0),
          _c_num(0),
          _cap(bqsize)
    {
    }

    void Equeue(const T &in)
    {
        {
            _mutex.Lock();
            while (isfull())
            {
                _p_num++;
                _full_wait.Wait(_mutex);
                std::cout << "生产者，进入休眠了: _psleep_num" << _p_num << std::endl;
                _p_num--;
            }

            _q.push(in);

            if (_c_num > 0)
            {
                _empty_wait.Signal();
                std::cout << "唤醒消费者" << std::endl;
            }   
            _mutex.Unlock();
        }
    }

    T Pop()
    {   
        T data;
        {
            //LockGuard lockguard(_mutex);
            _mutex.Lock();
            while(isempty())
            {
                _c_num++;
                _empty_wait.Wait(_mutex);
                std::cout << "消费者，进入休眠了: _psleep_num" << _p_num << std::endl;

                //std::cout
                _c_num--;
            }
            data = _q.front();
            _q.pop();

            if(_p_num > 0)
            {
                _full_wait.Signal();
                //std::cout
                std::cout << "唤醒生产者" << std::endl;
            }

            _mutex.Unlock();
        }
        return data;
    }

    ~BlockQueue()
    {
    }

private:
    std::queue<T> _q;
    Mutex _mutex;
    int _cap;
    int _p_num;
    int _c_num;

    Cond _full_wait;
    Cond _empty_wait;
};
